'''
Goes through given traffic file and locates packets with least amount
of differences from given single packet.
'''

import struct
import sys


def main(args):

    if ((not args) or (args[0] in ['-h', '--help'])):
        print "This script takes one packet as a source and tries to find packets with least amount of differences from given traffic file."
        print ""
        print "Takes two arguments:"
        print "1. Source packet, which is used for comparison."
        print "2. Traffic file, which is searched for similarities."
        print ""
        print "All of the files should be in pcap format."
        return

    try:
        source = open(args[0], 'r')
        target = open(args[1], 'r')
    except:
        print "Couldn't open provided pcap files."
        print "Exiting."
        return


    '''Handle the source packet'''

    header = source.read(8)
    reverse = False

    if "\xa1\xb2\xc3\xd4" in header and "\x00\x02\x00\x04" in header:
        reverse = False
    elif "\xd4\xc3\xb2\xa1" in header and "\x02\x00\x04\x00" in header:
        reverse = True
    else:
        print "Not a pcap-file."
        return    

    source.seek(24)
    header = ""
    data = ""
    pLen = 0
    counter = 1

    #Read the single source packet
    header = source.read(16)

    if reverse:
        header = reverse_header(header)

    pLen = struct.unpack('>I', header[8:12])[0]

    data = source.read(pLen)

    srcInfo = {'len':pLen, 'raw':data}

    print "Source packet parsed.\nlength: {}".format(srcInfo['len'])


    '''Handle the target packets'''

    if "\xa1\xb2\xc3\xd4" in header and "\x00\x02\x00\x04" in header:
        reverse = False
    elif "\xd4\xc3\xb2\xa1" in header and "\x02\x00\x04\x00" in header:
        reverse = True
    else:
        print "Not a pcap-file."
        return  

    target.seek(24)
    header = ""
    data = ""
    pLen = 0
    counter = 0
    hitsArr = []
    distance = 0
    currentMin = 65535
    i = 0

    while True:
        try:
            header = target.read(16)

            if len(header) != 16:
                break
            else:
                counter += 1

            if reverse:
                header = reverse_header(header)

            pLen = struct.unpack('>I', header[8:12])[0]

            data = target.read(pLen)

            #Compare packet data against source packet
            if (pLen < (srcInfo['len']+3)) and (pLen > (srcInfo['len']-3)):
                i = 0
                distance = 0
                while i < pLen:
                    try:
                        if data[i] != srcInfo['raw'][i]: 
                            distance += 1
                    except:
                        pass
                    i += 1
    
                if distance < (currentMin+2):
                    currentMin = distance
                    hitsArr.append([counter, distance])
                
        except KeyboardInterrupt:
            print "\n\nInterrupted, exiting.\n"
            break

    print "Scanned through {} packets.".format(counter)
    print "Minimum distance to source {}.\n\n".format(currentMin)

    for x in hitsArr:
        print "#{}, distance {}".format(x[0],x[1])


#Reverses pcap packet header
def reverse_header(hdr):
    header = (hdr[0:4][::-1]+
              hdr[4:8][::-1]+
              hdr[8:12][::-1]+
              hdr[12:16][::-1])
    return header


if __name__ == "__main__":
    main(sys.argv[1:])
